package com.marketlive.app.b2c.struts;
/*
(C) Copyright MarketLive. 2006. All rights reserved.
MarketLive is a trademark of MarketLive, Inc.
Warning: This computer program is protected by copyright law and international treaties.
Unauthorized reproduction or distribution of this program, or any portion of it, may result
in severe civil and criminal penalties, and will be prosecuted to the maximum extent
possible under the law.
*/

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.validator.Validator;
import org.apache.commons.validator.ValidatorException;
import org.apache.commons.validator.ValidatorResources;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionMessages;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionForm;
import org.apache.struts.util.RequestUtils;
import org.apache.struts.validator.Resources;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import java.util.Locale;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.ServletContext;

/**
 * Performs the validation defined in the validation.xml file, keyed on the
 * ActionMapping's path.
 */
public abstract class XmlValidatingDispatchAction extends ValidatingDispatchAction {

    /**
     * Page to pass to validator.  Not used.
     */
    private static int DEFAULT_PAGE = 0;
    /**
     * ServletContext storage keys used by Struts for the validations parameters. 
     */
    private static String SERVLET_CONTEXT_PARAM = "javax.servlet.ServletContext";
    private static String HTTP_SERVLET_REQUEST_PARAM = "javax.servlet.http.HttpServletRequest";
    private static String ACTION_MESSAGES_PARAM = "org.apache.struts.action.ActionMessages";
    /**
     * Logger
     */
    private static Log log = LogFactory.getLog(XmlValidatingDispatchAction.class);

    /**
     * Called by process to do action-based validation.  Default is to lookup the
     * validation rules based on the ActionMapping path in validation.xml.
     * To use a different key override the getValidationKey() method.
     *
     * @param mapping
     * @param form
     * @param request
     * @return
     */
    public ActionMessages validate(ActionMapping mapping, ActionForm form, HttpServletRequest request) {
        String validationKey = getValidationKey(mapping, request);
        return validate(mapping, form, request, validationKey);
    }

    /**
     * Performs validation using the specified key.
     *
     * @param mapping
     * @param form
     * @param request
     * @param validationKey
     * @return
     */
    protected ActionMessages validate(ActionMapping mapping, ActionForm form, HttpServletRequest request, String validationKey) {
        log.debug("doing validation with key: " + validationKey);

        ServletContext application = getServlet().getServletContext();
        ActionMessages errors = new ActionErrors();

        Validator validator = initValidator(validationKey, form, application, request, errors, DEFAULT_PAGE);

        try {
            validator.validate();
        } catch (ValidatorException e) {
            log.error(e.getMessage(), e);
        }

        return errors;
    }

    /**
     * Returns the Validation key.
     *
     * @param mapping The mapping used to select this instance
     * @param request The servlet request we are processing
     * @return validation key - the form element's name in this case
     */
    private String getValidationKey(ActionMapping mapping,
                                    HttpServletRequest request) {
        return mapping.getPath();
    }

    /**
     * Initialize the <code>Validator</code> to perform validation. This is a duplicate of 
     * the Struts static method, Resource.initValidator, except we use featureManager controlled
     * ValidatorResources instead of what is in the ServletContext.
     *
     * @param key The key that the validation rules are under (the form elements 
     * name attribute).
     * @param bean The bean validation is being performed on.
     * @param application servlet context
     * @param request The current request object.
     * @param errors The object any errors will be stored in.
     * @param page This in conjunction with  the page property of a 
     * <code>Field<code> can control the processing of fields.  If the field's 
     * page is less than or equal to this page value, it will be processed.
     */
    public static Validator initValidator(String key, Object bean, ServletContext application,
        HttpServletRequest request, ActionMessages errors, int page) {

        ValidatorResources resources = new ValidatorResources();
        // build the Validator    
        Validator validator = new Validator(resources, key);
        validator.setUseContextClassLoader(true);
        validator.setPage(page);
        Locale locale = RequestUtils.getUserLocale(request, null);
        validator.setParameter(SERVLET_CONTEXT_PARAM, application);
        validator.setParameter(HTTP_SERVLET_REQUEST_PARAM, request);
        validator.setParameter(Validator.LOCALE_PARAM, locale);
        validator.setParameter(ACTION_MESSAGES_PARAM, errors);
        validator.setParameter(Validator.BEAN_PARAM, bean);

        return validator;
    }
}
